package com.ruoyi.ichen.base.utils;

import com.ruoyi.ichen.base.exception.Exceptions;
import com.ruoyi.ichen.base.exception.WeCoreException;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.*;
import org.joda.time.format.DateTimeFormat;

import java.text.ParseException;
import java.util.*;

/**
 * @ClassName: DateUtils
 * @Description: 日期工具类
 * 
 * @author Venlentine
 * @Date: 2013年8月28日 下午4:21:04
 * @version
 * 
 *          <pre>
 * 修改记录:
 * 修改后版本		修改人		修改日期	修改内容
 * 2013年8月28日.1		Venlentine	2013年8月28日	Create
 * 2019年7月6日.1		Venlentine	2019年7月6日		Update
 *          </pre>
 *
 */
public class MyDateUtils {

	public static final String FULL_PATTERN = "yyyy-MM-dd HH:mm:ss";
	public static final String DATE_PATTERN = "yyyy-MM-dd";
	public static final String MONTH_PATTERN = "yyyy-MM";
	public static final String TIME_PATTERN = "HH:mm:ss";
	public static final String TIME_SHORT_PATTERN = "HH:mm";
	private static final TimeZone defaultTimeZone = TimeZone.getTimeZone("Asia/Shanghai");

	private enum TimeFormatEnum{
		FULL, DATE, TIME, TIME_SHORT, MONTH
	}

	private static Map<TimeFormatEnum, String> TimeFormatMap = new HashMap<TimeFormatEnum, String>(){{
		put(TimeFormatEnum.FULL, FULL_PATTERN);
		put(TimeFormatEnum.DATE, DATE_PATTERN);
		put(TimeFormatEnum.TIME, TIME_PATTERN);
		put(TimeFormatEnum.TIME_SHORT, TIME_SHORT_PATTERN);
		put(TimeFormatEnum.MONTH, MONTH_PATTERN);
	}};

	public enum TimePeriodEnum {
		YEAR, MONTH, DAY, HOUR, MINUTE, SECOND
	}

	public MyDateUtils() {
		// DateTimeZone.setDefault(DateTimeZone.forTimeZone(defaultTimeZone));
	}

	private static DateTime getJodaTime() {
		return new DateTime(DateTimeZone.forTimeZone(defaultTimeZone));
	}

	private static DateTime getJodaTime(Date date) {
		return new DateTime(date, DateTimeZone.forTimeZone(defaultTimeZone));
	}

	private static DateTime getJodaTime(long time) {
		return new DateTime(time, DateTimeZone.forTimeZone(defaultTimeZone));
	}

	/**
	 * 获取当前时间毫秒
	 * @return
	 */
	public static long getCurrentTimeMillis() {
		return getTimeMillis(null);
	}

	/**
	 * 获取当前时间
	 * 
	 * @return
	 */
	public static Date getCurrentDateTime() {
		return getJodaTime().toDate();
	}

	/**
	 * 获取当前日期
	 * 
	 * @return
	 */
	public static Date getCurrentDate() {
		return new LocalDate(getJodaTime()).toDate();
	}

	public static int getCurrentTimeUnit(TimePeriodEnum period){
		return getCurrentTimeUnit(period, null);
	}

	public static int getCurrentTimeUnit(TimePeriodEnum period, Date date){
		switch (period){
			case YEAR:
				return getJodaTime(date).getYear();
			case MONTH:
				return getJodaTime(date).getMonthOfYear();
			case HOUR:
				return getJodaTime(date).getHourOfDay();
			default:
				throw new WeCoreException("暂未实现");
		}
	}

	/**
	 * 获取毫秒
	 * @param date
	 * @return
	 */
	public static long getTimeMillis(Date date) {
		return getJodaTime(date).getMillis();
	}

	/**
	 * 获取微秒
	 * @param date
	 * @return
	 */
	public static long getTimestamp(Date date) {
		Long timeMillion = getJodaTime(date).getMillis();
		String timeMillionStr = timeMillion.toString();
		return Long.parseLong(timeMillionStr.substring(0, timeMillionStr.length() - 3));
	}

	/**
	 * 夜里12点
	 * @param date
	 * @return
	 */
	public static Date getZeroPointTime(Date date) {
		DateTime dt = getJodaTime(date).plusDays(1);
		DateTime zeroDT = new DateTime(dt.getYear(), dt.getMonthOfYear(), dt.getDayOfMonth(), 0, 0, 0);
		return zeroDT.toDate();
	}

	// =========== 字符串转换时间 ===========
	public static Date parseDate(String strDate, String format) {
		try {
			if (StringUtils.isBlank(strDate)) {
				return null;
			}
			DateTime dt = DateTimeFormat.forPattern(format).parseDateTime(strDate);
			return dt.toDate();
		} catch (Exception e) {
			Exceptions.handleException(e);
		}
		return null;
	}

	public static Date parseDate(String strDate) {
		return parseDate(strDate, DATE_PATTERN);
	}

	public static Date parseTime(String strDate) {
		return parseDate(strDate, TIME_PATTERN);
	}

	public static Date parseDateTime(String strDate) {
		return parseDate(strDate, FULL_PATTERN);
	}

	public static Date parseDateTime(long time) {
		try {
			DateTime dt = getJodaTime(time);
			return dt.toDate();
		} catch (Exception e) {
			Exceptions.handleException(e);
			return null;
		}
	}

	public static Date parseDateTimeUTC(String strDate) {
		return parseDate(strDate, "yyyy-MM-dd'T'HH:mm:ss'Z'");
	}

	// =========== 时间转换成字符串 ===========

	public static String getStrDateCustom(String format) {
		return getStrDateCustom(new Date(), format);
	}

	public static String getStrDateCustom(Date date, String format) {
		return getJodaTime(date).toString(format, Locale.CHINA);
	}

	public static String getStrDate() {
		return getStrDateTime(TimeFormatEnum.DATE, new Date());
	}

	public static String getStrDate(Date date) {
		return getStrDateTime(TimeFormatEnum.DATE, date);
	}

	/**
	 * 格式化当前日期时间
	 * @return
	 */
	public static String getStrDateTime() {
		return getStrDateTime(TimeFormatEnum.FULL, new Date());
	}

	public static String getStrDateTime(Object time) {
		return getStrDateTime(TimeFormatEnum.FULL, time);
	}

	public static String getStrTime(long time) {
		return getStrDateTime(TimeFormatEnum.TIME, time);
	}

	public static String getStrTimeShort(long time) {
		return getStrDateTime(TimeFormatEnum.TIME_SHORT, time);
	}

	public static String getStrMonth(Date date) {
		return getStrDateTime(TimeFormatEnum.MONTH, date);
	}

	/**
	 * 格式化日期时间
	 * @param time	只能接收Long和Date
	 * @return
	 */
	private static String getStrDateTime(TimeFormatEnum timeFormat, Object time) {
		if(time == null){
			throw new WeCoreException("Object对象为空");
		}

		if(time instanceof Long){
			String stime = time.toString();
			if(stime.length() != 13){
				throw new WeCoreException("Object对象Long长度不正确");
			}
			return getJodaTime(Long.parseLong(stime)).toString(TimeFormatMap.get(timeFormat), Locale.CHINA);

		}else if(time instanceof Date){
			Date dtime = (Date)time;
			return getJodaTime(dtime).toString(TimeFormatMap.get(timeFormat), Locale.CHINA);

		}else{
			throw new WeCoreException("Object格式不正确，只能接收Long和Date");
		}
	}

	// =========== 时间计算 ===========

	/**
	 * 小时换秒
	 * @param hour
	 * @return
	 */
	public static Long hourToSecond(Double hour) {
		return Double.valueOf(hour * 3600D).longValue();
	}

	/**
	 * 秒换小时
	 * @param millisecond
	 * @return
	 */
	public static Double millisecondToHour(Long millisecond) {
		return millisecond / 3600000D;
	}

	/**
	 * 增减当前时间
	 * @param period
	 * @param num		负数为减少
	 * @return
	 */
	public static Date addTimePeriod(TimePeriodEnum period, int num){
		return addTimePeriod(period, num, null);
	}

	/**
	 * 增减时间
	 * @param period
	 * @param num		负数为减少
	 * @param date
	 * @return
	 */
	public static Date addTimePeriod(TimePeriodEnum period, int num, Date date){
		DateTime dt = getJodaTime(date);
		switch (period){
			case SECOND:
				return dt.plusSeconds(num).toDate();
			case MINUTE:
				return dt.plusMinutes(num).toDate();
			case HOUR:
				return dt.plusHours(num).toDate();
			case DAY:
				return dt.plusDays(num).toDate();
			case MONTH:
				return dt.plusMonths(num).toDate();
			case YEAR:
				return dt.plusYears(num).toDate();
			default:
				throw new WeCoreException("未实现的功能");

		}
	}

	/**
	 * 获取时间与当前时间之间的时间差
	 * 
	 * @param date1
	 * @return
	 */
	public static int getTimePeriodDiff(TimePeriodEnum period, Date date1) {
		return getTimePeriodDiff(period, date1, getCurrentDateTime());
	}

	/**
	 * 获取两个时间之间的时间差
	 * @param date1 较小的时间
	 * @param date2 较大的时间
	 * @return 相差天数
	 * @throws ParseException
	 */
	public static int getTimePeriodDiff(TimePeriodEnum period, Date date1, Date date2) {
		DateTime dt1 = new DateTime(date1);
		DateTime dt2 = new DateTime(date2);

		if (period == TimePeriodEnum.DAY) {
			Period p = new Period(dt1, dt2, PeriodType.days());
			return Math.abs(p.getDays());
		} else if (period == TimePeriodEnum.HOUR) {
			Period p = new Period(dt1, dt2, PeriodType.hours());
			return Math.abs(p.getHours());
		} else if (period == TimePeriodEnum.MINUTE) {
			Period p = new Period(dt1, dt2, PeriodType.minutes());
			return Math.abs(p.getMinutes());
		} else if (period == TimePeriodEnum.SECOND) {
			Period p = new Period(dt1, dt2, PeriodType.seconds());
			return Math.abs(p.getSeconds());
		} else {
			Period p = new Period(dt1, dt2, PeriodType.days());
			return Math.abs(p.getDays());
		}
	}

	/**
	 * 判断时间是否相同
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static Boolean isSameDate(Date date1, Date date2) {
		DateTime dt1 = new DateTime(date1);
		DateTime dt2 = new DateTime(date2);
		return dt1.isEqual(dt2);
	}

	/**
	 * 判断时间过期(在当前时间之前)
	 * @param date
	 * @return
	 */
	public static Boolean isBeforeNow(Date date) {
		DateTime dt1 = new DateTime(date);
		return dt1.isBeforeNow();
	}

	/**
	 * 判断时间过期(在当前时间之后)
	 * @param date
	 * @return
	 */
	public static Boolean isAfterNow(Date date) {
		DateTime dt1 = new DateTime(date);
		return dt1.isAfterNow();
	}

	/**
	 * 判断时间是否在两个时间之间
	 * @param date1
	 * @param date2
	 * @param date
	 * @return
	 */
	public static Boolean isBetweenDate(Date date1, Date date2, Date date) {
		Interval i = new Interval(getJodaTime(date1), getJodaTime(date2));
		return i.contains(new DateTime(date));
	}

	/**
	 * 获取小时Map
	 * @return
	 */
	public static Map<Integer, String> getHours() {
		Map<Integer, String> hours = new HashMap<Integer, String>();
		for (int i = 1; i <= 24; i++) {
			hours.put(i, i + "点");
		}
		return hours;
	}

	/**
	 * 替换日期中的时间为当前时间
	 * @param date
	 * @return
	 */
	public static Date replaceDateWithCurrentTime(Date date) {
		String dateStr = getStrDate(date);
		String timeStr = getStrDateCustom(TIME_PATTERN);
		return parseDateTime(String.format("%s %s", dateStr, timeStr));
	}

	/**
	 * 替换日期中的时间为date2的时间
	 * @param date1
	 * @param date2
	 * @return
	 */
	public static Date replaceDateWithTime(Date date1, Date date2) {
		String dateStr = getStrDate(date1);
		String timeStr = getStrDateCustom(date2, TIME_PATTERN);
		return parseDateTime(String.format("%s %s", dateStr, timeStr));
	}

	/**
	 * 根据生日获取年龄
	 * @param birthday
	 * @return
	 */
	public static int getAge(Date birthday){
		return getCurrentTimeUnit(TimePeriodEnum.YEAR) - getCurrentTimeUnit(TimePeriodEnum.YEAR, birthday);
	}

	// =========== 特殊时间 ===========

	/**
	 * 获取月每一天
	 * @param month
	 * @return
	 */
	public static List<String> getDaysOfMonth(String month) {
		List<String> daysInMonthLabels = new ArrayList<String>();
		DateTime dateTime = DateTimeFormat.forPattern(MONTH_PATTERN).parseDateTime(month);
		LocalDate firstDay = dateTime.toLocalDate().withDayOfMonth(1);
		LocalDate nextMonthFirstDay = firstDay.plusMonths(1);
		while (firstDay.isBefore(nextMonthFirstDay)) {
			daysInMonthLabels.add(firstDay.toString(DATE_PATTERN));
			firstDay = firstDay.plusDays(1);
		}
		return daysInMonthLabels;
	}

	/**
	 * 获取今天的时间, 从 00:00:00 ~ 23:59:59
	 */
	public static Date[] getDayRange() {
		DateTime dt = getJodaTime();
		return new Date[]{dt.withTimeAtStartOfDay().toDate(), dt.millisOfDay().withMaximumValue().toDate()};
	}

	/**
	 * 获取本月
	 * @return
	 */
	public static Date[] getMonthRange() {
		DateTime dt = getJodaTime();
		LocalDate firstDayOfMonth = new LocalDate(dt.getYear(), dt.getMonthOfYear(), 1);
		LocalDate lastDayOfMonth = firstDayOfMonth.plusMonths(1).plusDays(-1);
		return new Date[] { firstDayOfMonth.toDate(), lastDayOfMonth.toDate() };
	}

	/**
	 * 获取本年
	 * @return
	 */
	public static Date[] getYearRange() {
		DateTime dt = getJodaTime();
		LocalDate firstDayOfYear = new LocalDate(dt.getYear(), 1, 1);
		LocalDate lastDayOfYear = firstDayOfYear.plusYears(1).plusDays(-1);
		return new Date[] { firstDayOfYear.toDate(), lastDayOfYear.toDate() };
	}

	/**
	 * 本周
	 * @return
	 */
	public static Date[] getWeekRange() {
		DateTime dt = getJodaTime();
		LocalDate firstDayOfWeek = new LocalDate(dt.withDayOfWeek(DateTimeConstants.MONDAY));// .minusDays(1)
		LocalDate lastDayOfWeek = new LocalDate(dt.withDayOfWeek(DateTimeConstants.SUNDAY));// .plusDays(0)
		return new Date[] { firstDayOfWeek.toDate(), lastDayOfWeek.toDate() };
	}

	/**
	 * 获取上月
	 * @return
	 */
	public static Date[] getLastMonthRange() {
		DateTime dt = getJodaTime();
		dt = dt.minusMonths(1);
		LocalDate firstDayOfMonth = new LocalDate(dt.getYear(), dt.getMonthOfYear(), 1);
		LocalDate lastDayOfMonth = firstDayOfMonth.plusMonths(1).plusDays(-1);
		return new Date[] { firstDayOfMonth.toDate(), lastDayOfMonth.toDate() };
	}

	/**
	 * 获取上周
	 * @return
	 */
	public static Date[] getLastWeekRange() {
		DateTime dt = getJodaTime();
		dt = dt.minusWeeks(1);
		LocalDate firstDayOfWeek = new LocalDate(dt.withDayOfWeek(DateTimeConstants.MONDAY));// .minusDays(1)
		LocalDate lastDayOfWeek = new LocalDate(dt.withDayOfWeek(DateTimeConstants.SUNDAY));// .plusDays(0)
		return new Date[] { firstDayOfWeek.toDate(), lastDayOfWeek.toDate() };
	}

	/**
	 * 获取一天小时列表
	 * [00:00, 01:00, 02:00 ... 23:00]
	 * [07-06 00:00, 07-06 01:00] date不为null时
	 * @return
	 */
	public static List<String> getHoursTimeOfDate(Date date) {
		List<String> hourTimeList = new ArrayList<String>();
		DateTime dateTime = getJodaTime(date);
		DateTime firstHourTime = dateTime.withTimeAtStartOfDay();
		final DateTime nextDayFirstHourTime = firstHourTime.plusDays(1);
		while (firstHourTime.isBefore(nextDayFirstHourTime)) {
			if(date == null) {
				hourTimeList.add(firstHourTime.toString(TIME_SHORT_PATTERN));
			}else{
				hourTimeList.add(firstHourTime.toString("MM-dd HH:mm"));
			}
			firstHourTime = firstHourTime.plusHours(1);
		}
		return hourTimeList;
	}

	/**
	 * 获取当前年月份列表
	 * [2019-01, 2019-02 ... 2019-12]
	 * @param date
	 * @return
	 */
	public static List<String> getMonthsOfYear(Date date) {
		List<String> monthList = new ArrayList<String>();
		DateTime jodaTime = getJodaTime(date);
		LocalDate firstMonth = jodaTime.toLocalDate().withDayOfMonth(1).withMonthOfYear(1);
		final LocalDate nextYearFirstMonth = firstMonth.plusYears(1);
		while (firstMonth.isBefore(nextYearFirstMonth)) {
			monthList.add(firstMonth.toString(MONTH_PATTERN));
			firstMonth = firstMonth.plusMonths(1);
		}
		return monthList;
	}

	/**
	 * 获取两个日期之间的天数列表
	 * [2019-07-06, 2019-07-07, 2019-07-08 ... 2019-07-20]
	 * @param sdate
	 * @param edate
	 * @return
	 */
	public static List<String> getDaysBetweenDate(Date sdate, Date edate) {
		List<String> days = new ArrayList<String>();
		DateTime sdateTime = getJodaTime(sdate);
		DateTime edateTime = getJodaTime(edate);
		while (sdateTime.isBefore(edateTime)) {
			days.add(sdateTime.toString(DATE_PATTERN));
			sdateTime = sdateTime.plusDays(1);
		}
		days.add(edateTime.toString(DATE_PATTERN));
		return days;

	}

	public static void main(String[] args) {
		/*Integer expireInterval = 3600;
		Long a = MyDateUtils.addSeconds(expireInterval).getTime();
		Long b = MyDateUtils.getCurrentTimeMillis();
		System.out.println(MyDateUtils.getExpireTime(getCurrentDateTime()));*/
		Long dt = parseDate("2019-07-23 19:00:00","yyyy-MM-dd HH:mm:ss").getTime();
		System.out.println(dt);
		System.out.println(new Date(dt));
//		System.out.println(getAge(parseDate("1999-12-11")));
	}
}
